home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / DCLAP 6d / dclap6d / network / ncsasock / sock_std.c < prev    next >
Text File  |  1996-07-05  |  9KB  |  565 lines

  1. /*
  2.  * BSD-style socket emulation library for the Mac
  3.  * Original author: Tom Milligan
  4.  * Current author: Charlie Reiman - creiman@ncsa.uiuc.edu
  5.  *
  6.  * This source file is placed in the public domian.
  7.  * Any resemblance to NCSA Telnet, living or dead, is purely coincidental.
  8.  *
  9.  *      National Center for Supercomputing Applications
  10.  *      152 Computing Applications Building
  11.  *      605 E. Springfield Ave.
  12.  *      Champaign, IL  61820
  13.  */
  14.  
  15. /*
  16.  *    A really hacked up stdio interface for the MacTCP socket library
  17.  *    
  18.  *    routines:
  19.  *
  20.  *        fdopen
  21.  *        fileno
  22.  *        fgetc
  23.  *        ungetc
  24.  *        fread
  25.  *        fputc
  26.  *        fwrite
  27.  *        fprintf
  28.  *        fflush
  29.  *        fclose
  30.  *        ferror
  31.  *        feof
  32.  *        clearerr
  33.  *
  34.  *    hacks:
  35.  *
  36.  *        the stdio data are stored in the socket descriptor. fdopen() calls
  37.  *        simply return a pointer to the descriptor. The first call per
  38.  *        socket initializes stdio for both read and write. (The "rw"
  39.  *        parameter to fdopen() is ignored.) The first fclose() will destroy
  40.  *        all stdio streams open on the socket.
  41.  *
  42.  *        ungetc will return EOF if the buffer is full.
  43.  *
  44.  *        printf uses a fixed size buffer to build the message.
  45.  *
  46.  *    non-blocking i/o
  47.  *
  48.  *        all read operations which would block return EOF with errno set 
  49.  *        to EWOULDBLOCK courtesy of the read() call.
  50.  *
  51.  *        write operations hide the EINPROGRESS 'error' from the write()
  52.  *        call, but generate EALREADY when a second operation is attempted.
  53.  *
  54.  *        NOTE: the write() call ties up the stdio buffer until it finishes. 
  55.  *
  56.  *        How to code a write operation....
  57.  *
  58.  *        for(;;)
  59.  *        {
  60.  *            errno = 0;
  61.  *            if (s_fprintf(stream, blah, blah) != EOF)
  62.  *                break;
  63.  *            
  64.  *            if (errno == EALREADY)
  65.  *            {
  66.  *                Handle_Mac_Events();
  67.  *                continue;
  68.  *            }
  69.  *            else
  70.  *            {
  71.  *                a real error ...
  72.  *            }
  73.  *        }
  74.  *
  75.  *        How to code a read ...
  76.  *
  77.  *        for(;;)
  78.  *        {
  79.  *            errno = 0;
  80.  *            c = s_fgetc(inFile);
  81.  *            if (c != EOF)
  82.  *                break;
  83.  *            if (errno == EWOULDBLOCK || errno == EALREADY)
  84.  *            {
  85.  *                Handle_Mac_Events();
  86.  *                continue;
  87.  *            }
  88.  *            else if (errno == 0)
  89.  *            {
  90.  *                a real end of file ...
  91.  *            }
  92.  *            else
  93.  *            {
  94.  *                a real error ...
  95.  *            }
  96.  *        }
  97.  */
  98.  
  99. #ifdef USEDUMP
  100. # pragma load "Socket.dump"
  101.  
  102. #else
  103. # include <Events.h>
  104. # include <Memory.h>
  105. # include <Types.h>
  106. # include <Stdio.h>
  107.  
  108. # include <s_types.h>
  109. # include <neti_in.h>
  110. #ifdef COMP_CODEWAR
  111. #define NOWAY
  112. #undef EDOM
  113. #undef ERANGE
  114. #endif
  115. # include <neterrno.h>
  116. # include <s_socket.h>
  117. # include <s_time.h>
  118. # include <s_uio.h>
  119.  
  120. # include "sock_str.h"
  121. # include "sock_int.h"
  122.  
  123. /*# include <sock_ext.h>*/
  124. # include <unixlib.h>
  125.  
  126. #endif
  127.  
  128. #include <StdArg.h>
  129.  
  130. extern SocketPtr sockets;
  131. extern SpinFn aspinroutine;
  132.  
  133. /*
  134.  *    tuneable constants
  135.  */
  136. #define SOCK_IOINBUF_SIZE        128        /* Size of stdio input buffer */
  137. #define SOCK_IOOUTBUF_SIZE        128        /* Size of stdio output buffer */
  138.  
  139. static struct timeval select_poll = {0,0};
  140.  
  141. /*
  142.  *    s_fdopen() - open a stdio stream on a socket
  143.  */
  144. Ptr s_fdopen(
  145.     int fd,
  146.     char *type)
  147. {
  148. #pragma unused(type)
  149.     SocketPtr sp;
  150.     
  151. #if    SOCK_STDIO_DEBUG >= 3
  152.     dprintf("s_fdopen: opening on fd %d\n",fd);
  153. #endif
  154.     if (! sock_good_fd(fd)) 
  155.     {
  156.         (void)sock_err(EBADF);
  157.         return(NULL);
  158.     }
  159.         
  160.     sp = sockets+fd;
  161.     if (is_stdio(sp)) 
  162.         return((Ptr)sp);
  163.     
  164.     sp->inbuf = (char *)NewPtr(SOCK_IOINBUF_SIZE);
  165.     if (sp->inbuf == NULL) 
  166.     {
  167.         errno = ENOMEM;
  168.         return(NULL);
  169.     }
  170.     sp->outbuf = (char *)NewPtr(SOCK_IOOUTBUF_SIZE);
  171.     if (sp->outbuf == NULL) 
  172.     {
  173.         DisposPtr(sp->inbuf);
  174.         errno = ENOMEM;
  175.         return(NULL);
  176.     }
  177.     
  178.     sp->inbufptr  = sp->inbuf;
  179.     sp->inbufcount  = 0;
  180.     sp->outbufptr = sp->outbuf;
  181.     sp->outbufcount = 0;
  182.     
  183.     sp->ioerr = false;
  184.     sp->ioeof = false;
  185.  
  186.     return((Ptr)sp);
  187. }
  188.  
  189. /*
  190.  *    s_fileno()
  191.  */
  192. int s_fileno(
  193.     SocketPtr sp)
  194. {
  195. #if    SOCK_STDIO_DEBUG >= 3
  196.     dprintf("s_fileno:  on FILE * %08x\n",sp);
  197. #endif
  198.     if (! is_stdio(sp)) 
  199.     {
  200.         return(sock_err(EBADF));
  201.         return(EOF);
  202.     }
  203. #if    SOCK_STDIO_DEBUG >= 5
  204.     dprintf("   returning fd %d\n",sp->fd);
  205. #endif
  206.     return(sp->fd);
  207. }
  208.  
  209.  
  210. static int stdio_read(
  211.     SocketPtr sp,
  212.     char *buffer,
  213.     int buflen);
  214.  
  215. /*
  216.  *    s_fgetc()
  217.  *
  218.  */
  219. int s_fgetc(
  220.     SocketPtr sp)
  221. {
  222.     char c;    
  223.         
  224.     if (stdio_read(sp, &c, 1) != 1)
  225.         return(EOF);
  226.         
  227.     return(c);
  228. }
  229.  
  230. /*
  231.  *    s_ungetc()
  232.  *
  233.  */
  234. int s_ungetc(
  235.     char c,
  236.     SocketPtr sp)
  237. {
  238.     
  239. #if    SOCK_STDIO_DEBUG >=3
  240.     dprintf("s_ungetc: %08x\n",sp);
  241. #endif
  242.  
  243.     if (! is_stdio(sp)) 
  244.     {
  245.         (void)sock_err(EBADF);
  246.         return(EOF);
  247.     }
  248.  
  249.     if (sp->ioeof)        /* Once an EOF; Always an EOF */
  250.         return(EOF);
  251.         
  252.     /*
  253.      *    Pop onto buffer, if there is room. 
  254.      */
  255.     if (sp->inbufptr == sp->inbuf)
  256.         return(EOF);
  257.     else 
  258.     {
  259.         *(sp->inbufptr++) = c;
  260.         sp->inbufcount++;
  261.         return(0);
  262.     }
  263. }
  264.  
  265. /*
  266.  *    s_fread()
  267.  */
  268. int s_fread(
  269.     char *buffer,
  270.     int size,
  271.     int nitems,
  272.     SocketPtr sp)
  273. {
  274.     return(stdio_read(sp, buffer, size*nitems));
  275. }
  276.     
  277. /*
  278.  *    stdio_read()
  279.  *
  280.  *    Buffered i/o.  Read buflen chars into buf.
  281.  *  Returns length read, EOF on error.
  282.  */
  283. static int stdio_read(
  284.     SocketPtr sp,
  285.     char *buffer,
  286.     int buflen)
  287. {
  288.     unsigned long tocopy;
  289.     Ptr buf;
  290.     unsigned long len;
  291.     int cache = false;    /* a flag ===> read into sp->inbuf */
  292.  
  293. #if    SOCK_STDIO_DEBUG >=3
  294.     dprintf("stdio_read: %08x for %d bytes\n",sp,buflen);
  295. #endif    
  296.  
  297.     if (! is_stdio(sp)) 
  298.     {
  299.         (void)sock_err(EBADF);
  300.         return(EOF);
  301.     }
  302.  
  303.     if (sp->ioeof)        /* Once an EOF; Always an EOF */
  304.         return(EOF);
  305.  
  306.     /*
  307.      *    return already buffered characters
  308.      */
  309.     if (sp->inbufcount != 0) 
  310.     {
  311.         tocopy = min(sp->inbufcount, buflen);
  312.         bcopy(sp->inbufptr, buffer, tocopy);
  313.         sp->inbufptr += tocopy;
  314.         sp->inbufcount -= tocopy;
  315.         return(tocopy);
  316.     }
  317.  
  318.     if (buflen > SOCK_IOINBUF_SIZE) 
  319.     {
  320.         /*
  321.          *    Read into user's buffer
  322.          */
  323.         buf = buffer;
  324.         len = buflen;
  325.     }
  326.     else 
  327.     {
  328.         /*
  329.          *    Read into stdio buffer
  330.          */
  331.         cache = true;
  332.         buf     = sp->inbuf;
  333.         len        = SOCK_IOINBUF_SIZE;
  334.     }
  335.  
  336.     len = s_read(sp->fd, buf, len);
  337.     switch(len) 
  338.     {
  339.         case -1:
  340.             sp->ioerr = true;
  341.             return(EOF);
  342.             
  343.         case 0:
  344.             sp->ioeof = true;
  345.             return(EOF);
  346.     }
  347.     if (cache) 
  348.     {
  349.         tocopy = min(buflen, len);
  350.         bcopy(sp->inbuf, buffer, tocopy);    /* copy to client's buffer */
  351.         sp->inbufcount     = len - tocopy;
  352.         sp->inbufptr     = sp->inbuf + tocopy;
  353.         return(tocopy);
  354.     }
  355.     return(len);            
  356. }
  357.  
  358.  
  359.  
  360. static int stdio_write(
  361.     SocketPtr sp,
  362.     char *buffer,
  363.     unsigned long buflen);
  364.  
  365. /*
  366.  *    s_fputc()
  367.  *
  368.  */
  369. int s_fputc(
  370.     char c,
  371.     SocketPtr sp)
  372. {
  373.     if (stdio_write(sp, &c, 1) == EOF)
  374.         return(EOF);
  375.         
  376.     return(c);
  377. }
  378.                 
  379. /*
  380.  *    s_fprintf()
  381.  * Modified to use StdArg macros by Charlie Reiman
  382.  * Wednesday, August 8, 1990 2:52:31 PM
  383.  *
  384.  */
  385. int s_fprintf(
  386.     SocketPtr sp,
  387.     char *fmt,
  388.     ...)
  389. {
  390.     va_list    nextArg;
  391.     int len;
  392.     char buf[1000];
  393.     
  394.     va_start(nextArg,fmt);
  395.     
  396.     (void) vsprintf(buf,fmt,nextArg);
  397.     len = strlen(buf);
  398.     return(stdio_write(sp, buf, len));
  399. }
  400.  
  401. /*
  402.  *    s_fwrite()
  403.  *
  404.  */
  405.  
  406. int s_fwrite(
  407.     char *buffer,
  408.     int size,
  409.     int nitems,
  410.     SocketPtr sp)
  411. {
  412.     return(stdio_write(sp, buffer, size*nitems));
  413. }
  414.  
  415. /*
  416.  *    stdio_write()
  417.  *
  418.  *    Buffered i/o.  Move buflen chars into stdio buf., writing out as necessary.
  419.  *    Returns # of characters written, or EOF.
  420.  */
  421. static int stdio_write(
  422.     SocketPtr sp,
  423.     char *buffer,
  424.     unsigned long buflen)
  425. {
  426.     long buffree;
  427.     struct iovec iov[2];
  428.     
  429. #if    SOCK_STDIO_DEBUG >=3
  430.     dprintf("stdio_write: %08x for %d bytes\n",sp,buflen);
  431. #endif    
  432.  
  433.     if (! is_stdio(sp))
  434.     {
  435.         (void) sock_err(EBADF);
  436.         return(EOF);
  437.     }
  438.     
  439.     /* will the new stuff fit in the buffer? */
  440.     buffree = SOCK_IOOUTBUF_SIZE - sp->outbufcount;
  441.     if (buflen < buffree)
  442.     {
  443.         /* yes...add it in */
  444.         bcopy(buffer, sp->outbufptr, buflen);
  445.         sp->outbufptr += buflen;
  446.         sp->outbufcount += buflen;
  447.         return(buflen);
  448.     }
  449.     else
  450.     {
  451.         /* no...send both buffers now */
  452.         iov[0].iov_len = sp->outbufcount;
  453.         iov[0].iov_base = sp->outbuf;
  454.         iov[1].iov_len = buflen;
  455.         iov[1].iov_base = buffer;
  456.         /* hide the 'error' generated by a non-blocking write */
  457.         if (s_writev(sp->fd,&iov[0],2) < 0 && errno != EINPROGRESS)
  458.         {
  459.             sp->ioerr = true;
  460.             return(EOF);
  461.         }
  462.  
  463.         sp->outbufptr = sp->outbuf;
  464.         sp->outbufcount = 0;
  465.  
  466.         return(buflen);
  467.     }
  468. }
  469.  
  470. /*
  471.  *    s_fflush()
  472.  *
  473.  */
  474. int s_fflush(
  475.     SocketPtr sp)
  476. {
  477. #if    SOCK_STDIO_DEBUG >=3
  478.     dprintf("s_fflush: %08x\n",sp);
  479. #endif
  480.     if (! is_stdio(sp))
  481.     {
  482.         (void)sock_err(EBADF);
  483.         return(EOF);
  484.     }
  485.     
  486.     if (sp->outbufcount == 0)
  487.         return(0);
  488.  
  489.     if (s_write(sp->fd,sp->outbuf,sp->outbufcount) < 0)
  490.         /* hide the 'error' generated by non-blocking I/O */
  491.         if (errno != EINPROGRESS)
  492.         {
  493.             sp->ioerr = true;
  494.             return(EOF);
  495.         }
  496.  
  497.     sp->outbufptr = sp->outbuf;
  498.     sp->outbufcount = 0;
  499.     return(0);
  500. }
  501.  
  502. /*
  503.  *    s_fclose() - close the stdio stream AND the underlying socket
  504.  */
  505. int s_fclose(
  506.     SocketPtr sp)
  507. {    
  508. #if    SOCK_STDIO_DEBUG >=3
  509.     dprintf("s_fclose: %08x\n",sp);
  510. #endif
  511.     
  512.     if (s_fflush(sp) == EOF) /* flush validates sp */
  513.         return(EOF);
  514.  
  515.     if (sp->inbuf != NULL) DisposPtr(sp->inbuf);
  516.     if (sp->outbuf != NULL) DisposPtr(sp->outbuf);
  517.     
  518.     return(s_close(sp->fd));
  519. }
  520.  
  521. /*
  522.  *    s_ferror()
  523.  */
  524. int s_ferror(
  525.     SocketPtr sp)
  526. {
  527.     if (! is_stdio(sp))
  528.     {
  529.         (void)sock_err(EBADF);
  530.         return(EOF);
  531.     }
  532.     return(sp->ioerr);
  533. }
  534.  
  535. /*
  536.  *    s_feof()
  537.  */
  538. int s_feof(
  539.     SocketPtr sp)
  540. {
  541.     if (! is_stdio(sp))
  542.     {
  543.         (void)sock_err(EBADF);
  544.         return(EOF);
  545.     }    
  546.     return(sp->ioeof);
  547. }
  548.  
  549. /*
  550.  *    s_clearerr()
  551.  */
  552. int s_clearerr(
  553.     SocketPtr sp)
  554. {    
  555.     if (! is_stdio(sp))
  556.     {
  557.         (void)sock_err(EBADF);
  558.         return(EOF);
  559.     }
  560.     sp->ioerr = false;
  561.     sp->ioeof = false;
  562.     return (0);
  563. }
  564.  
  565.